package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

func main() {
	body := map[string]interface{}{
		"user":     "zhang",
		"age":      10,
		"password": "12345",
	}

	res, err := json.Marshal(body)
	if err != nil {
		log.Fatal("json marshal err:", err)
	}
	fmt.Println(string(res))

	key := "java"
	nextCursor := "0"
	//requestBody := fmt.Sprintf(`{"key_word": "%s", "id_type": 0, "cursor": "%s", "limit": 20, "search_type": 0}`, key, nextCursor)
	rawUrl := "https://apinew.juejin.im/search_api/v1/search"
	header := map[string]string{
		"User-Agent":      "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0",
		"Accept":          "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
		"Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
		"Accept-Encoding": "gzip, deflate, br",
		"Referer":         "https://juejin.im/search?query=" + key,
		"Content-Type":    "application/json",
		"Origin":          "https://juejin.im",
		"Connection":      "keep-alive",
		"Cookie":          "Hm_lvt_93bbd335a208870aa1f296bcd6842e5e=1585649229,1587023263; gr_user_id=7ff105a2-c311-4b09-8e5c-863db5cd60e9; _ga=GA1.2.1122042631.1585649230; MONITOR_WEB_ID=2c1db46d-5304-448e-bc50-bf8468205920; _gid=GA1.2.922206982.1599204376; passport_auth_status=897f38c36d5cb93bb74a60a160e95ab4%2C; sid_guard=8484d7c1ac371660428a885a45eb3c65%7C1599207068%7C5184000%7CTue%2C+03-Nov-2020+08%3A11%3A08+GMT; uid_tt=0663d12bb072ab748608a59eabe192f3; uid_tt_ss=0663d12bb072ab748608a59eabe192f3; sid_tt=8484d7c1ac371660428a885a45eb3c65; sessionid=8484d7c1ac371660428a885a45eb3c65; sessionid_ss=8484d7c1ac371660428a885a45eb3c65",
		"TE":              "Trailers",
	}
	requestBody := map[string]interface{}{
		"key_word":    key,
		"id_type":     0,
		"cursor":      nextCursor,
		"limit":       20,
		"search_type": 0,
	}

	result, err := Request(rawUrl, "POST", requestBody, header, 25)
	if err != nil {
		log.Fatal("postJson err: ", err)
	}

	fmt.Println(result)
}

// 简单封装一个Http请求方法
// rawUrl 请求的接口地址
// method 请求的方法，GET/POST
// bodyMap 请求的 body 内容
// header 请求的头信息
// timeout 超时时间
func Request(rawUrl, method string, bodyMaps map[string]interface{}, headers map[string]string, timeout time.Duration) (result string, err error) {
	if timeout <= 0 {
		timeout = 5
	}
	client := &http.Client{
		Timeout: timeout * time.Second,
	}
	// 请求的 body 内容
	// 判断headers头信息是否存在content-type:application/json
	//data := url.Values{}
	var pIsJson *bool
	var isJson bool
	pIsJson = new(bool)
	for key, value := range headers {
		if strings.ToLower(key) == "content-type" && strings.ToLower(value) == "application/json" {
			*pIsJson = true
			isJson = true
		}
	}

	//var sendBody io.Reader
	//if *pIsJson {
	//	res, err := json.Marshal(bodyMaps)
	//	if err != nil {
	//		log.Fatal("json marshal err:", err)
	//	}
	//	sendBody = bytes.NewBuffer(res)
	//} else {
	//	sendBody = strings.NewReader(data.Encode())
	//}

	//_, ok := headers["Content-Type"]
	var sendBody io.Reader
	if isJson {
		res, errJson := json.Marshal(bodyMaps)
		if errJson != nil {
			err = errJson
			return
		}
		sendBody = bytes.NewBuffer(res)
	} else {
		data := url.Values{}
		for key, value := range bodyMaps {
			// interface 转 string
			str, errInter := interfaceToString(value)
			if errInter != nil {
				err = errInter
				return
			}
			data.Set(key, str)
		}
		sendBody = strings.NewReader(data.Encode())
	}

	//if _, ok := headers["content-type"]; ok && headers["content-type"] == "application/json" {
	//	res, err := json.Marshal(bodyMaps)
	//	if err != nil {
	//		log.Fatal("json marshal err:", err)
	//	}
	//	sendBody := bytes.NewBuffer(res)
	//} else {
	//	data := url.Values{}
	//	for key, value := range bodyMaps {
	//		// interface 转 string
	//		data.Set(key, value.(string))
	//	}
	//	sendBody := strings.NewReader(data.Encode())
	//}
	// 提交请求
	request, err1 := http.NewRequest(method, rawUrl, sendBody) // URL-encoded payload
	if err1 != nil {
		err = err1
		return
	}
	// 增加header头信息
	for key, val := range headers {
		request.Header.Set(key, val)
	}
	// 处理返回结果
	response, _ := client.Do(request)
	defer response.Body.Close()

	if response.StatusCode != http.StatusOK {
		return "", fmt.Errorf("get content failed status code is %d ", response.StatusCode)
	}
	buf := make([]byte, 4096)
	for {
		n, err2 := response.Body.Read(buf)
		if n == 0 {
			break
		}
		if err2 != nil && err2 != io.EOF {
			err = err2
			return
		}
		// 累加循环读取的 buf 数据，存入 result 中
		result += string(buf[:n])
	}
	return
}

//func getRequestBody(contentType string) io.Reader {
//	// 判断headers头信息是否存在content-type:application/json
//	if _, ok := headers["content-type"]; ok && headers["content-type"] == "application/json" {
//		res, err := json.Marshal(bodyMaps)
//		if err != nil {
//			log.Fatal("json marshal err:", err)
//		}
//		return bytes.NewBuffer(res)
//	} else {
//		data := url.Values{}
//		for key, value := range bodyMaps {
//			// interface 转 string
//			data.Set(key, value.(string))
//		}
//		return strings.NewReader(data.Encode())
//	}
//}

func interfaceToString(unknown interface{}) (str string, err error) {
	// interface 转 string
	switch unknown.(type) {
	case int:
		str = strconv.Itoa(unknown.(int))
	case string:
		str = unknown.(string)
	case byte:
		str = string(unknown.([]byte))
	default:
		err = errors.New("type not supported;Only support int/string/[]byte")
	}
	return str, err
}
